package com.dataexa.ky.service.mxgraph.parser;
import com.dataexa.ky.service.mxgraph.bo.*;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

import com.dataexa.ky.service.mxgraph.bo.MxGraph.MxElement;
import com.dataexa.ky.service.mxgraph.bo.MxGraph.Rect;
import com.dataexa.ky.service.mxgraph.bo.MxGraph.RoundRect;
import com.dataexa.ky.service.mxgraph.bo.MxGraph.Ellipse;
import com.dataexa.ky.service.mxgraph.bo.MxGraph.Text;
import com.dataexa.ky.service.mxgraph.bo.MxGraph.Move;
import com.dataexa.ky.service.mxgraph.bo.MxGraph.Line;
import com.dataexa.ky.service.mxgraph.bo.MxGraph.Stroke;
import com.dataexa.ky.service.mxgraph.bo.MxGraph.FillStroke;
import com.dataexa.ky.service.mxgraph.bo.MxGraph.FillColor;
import com.dataexa.ky.service.mxgraph.bo.MxGraph.StrokeColor;
import com.dataexa.ky.service.mxgraph.bo.MxGraph.FontFamily;
import com.dataexa.ky.service.mxgraph.bo.MxGraph.FontSize;
import com.dataexa.ky.service.mxgraph.bo.MxGraph.Restore;
import com.dataexa.ky.service.mxgraph.bo.MxGraph.Begin;
import com.dataexa.ky.service.mxgraph.bo.MxGraph.Close;
import com.dataexa.ky.service.mxgraph.bo.MxGraph.ShadowColor;
import com.dataexa.ky.service.mxgraph.bo.MxGraph.ShadowAlpha;
import com.dataexa.ky.service.mxgraph.bo.MxGraph.ShadowOffset;
import com.dataexa.ky.service.mxgraph.bo.MxGraph.Translate;
import com.dataexa.ky.service.mxgraph.bo.MxGraph.Scale;
import com.dataexa.ky.service.mxgraph.bo.MxGraph.Save;




public class MxGraphParser {
    public static MxGraph parse(String xml) throws Exception {
        SAXParserFactory factory = SAXParserFactory.newInstance();
        SAXParser parser = factory.newSAXParser();
        MxGraphHandler handler = new MxGraphHandler();
        parser.parse(new InputSource(new StringReader(xml)), handler);
        return handler.getGraph();
    }

    static class MxGraphHandler extends DefaultHandler {
        private MxGraph graph = new MxGraph();
        private Stack<List<MxElement>> elementStack = new Stack<>();
        private Stack<FillColor> fillColorStack = new Stack<>();
        private Stack<StrokeColor> strokeColorStack = new Stack<>();
        private Stack<FontFamily> fontFamilyStack = new Stack<>();
        private Stack<FontSize> fontSizeStack = new Stack<>();

        public MxGraph getGraph() {
            return graph;
        }

        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
            switch (qName) {
                case "output":
                    elementStack.push(graph.getElements());
                    break;
                case "fontfamily":
                    FontFamily fontFamily = new FontFamily();
                    fontFamily.setFamily(attributes.getValue("family"));
                    graph.setFontFamily(fontFamily);
                    fontFamilyStack.push(fontFamily);
                    break;
                case "fontsize":
                    FontSize fontSize = new FontSize();
                    fontSize.setSize(Double.parseDouble(attributes.getValue("size")));
                    graph.setFontSize(fontSize);
                    fontSizeStack.push(fontSize);
                    break;
                case "shadowcolor":
                    ShadowColor shadowColor = new ShadowColor();
                    shadowColor.setColor(attributes.getValue("color"));
                    graph.setShadowColor(shadowColor);
                    break;
                case "shadowalpha":
                    ShadowAlpha shadowAlpha = new ShadowAlpha();
                    shadowAlpha.setAlpha(Double.parseDouble(attributes.getValue("alpha")));
                    graph.setShadowAlpha(shadowAlpha);
                    break;
                case "shadowoffset":
                    ShadowOffset shadowOffset = new ShadowOffset();
                    shadowOffset.setDx(Double.parseDouble(attributes.getValue("dx")));
                    shadowOffset.setDy(Double.parseDouble(attributes.getValue("dy")));
                    graph.setShadowOffset(shadowOffset);
                    break;
                case "translate":
                    Translate translate = new Translate();
                    translate.setDx(Double.parseDouble(attributes.getValue("dx")));
                    translate.setDy(Double.parseDouble(attributes.getValue("dy")));
                    graph.setTranslate(translate);
                    break;
                case "scale":
                    Scale scale = new Scale();
                    scale.setScale(Double.parseDouble(attributes.getValue("scale")));
                    graph.setScale(scale);
                    break;
                case "save":
                    elementStack.push(new ArrayList<>());
                    graph.getElements().add(new Save());
                    break;
                case "restore":
                    if (!elementStack.isEmpty()) {
                        elementStack.pop();
                    }
                    if (!fillColorStack.isEmpty()) fillColorStack.pop();
                    if (!strokeColorStack.isEmpty()) strokeColorStack.pop();
                    if (!fontFamilyStack.isEmpty()) fontFamilyStack.pop();
                    if (!fontSizeStack.isEmpty()) fontSizeStack.pop();
                    graph.getElements().add(new Restore());
                    break;
                case "strokecolor":
                    StrokeColor strokeColor = new StrokeColor();
                    strokeColor.setColor(attributes.getValue("color"));
                    strokeColorStack.push(strokeColor);
                    break;
                case "fillcolor":
                    FillColor fillColor = new FillColor();
                    fillColor.setColor(attributes.getValue("color"));
                    fillColorStack.push(fillColor);
                    break;
                case "begin":
                    graph.getElements().add(new Begin());
                    break;
                case "move":
                    Move move = new Move();
                    move.setX(Double.parseDouble(attributes.getValue("x")));
                    move.setY(Double.parseDouble(attributes.getValue("y")));
                    graph.getElements().add(move);
                    break;
                case "line":
                    Line line = new Line();
                    line.setX(Double.parseDouble(attributes.getValue("x")));
                    line.setY(Double.parseDouble(attributes.getValue("y")));
                    graph.getElements().add(line);
                    break;
                case "stroke":
                    graph.getElements().add(new Stroke());
                    break;
                case "fillstroke":
                    graph.getElements().add(new FillStroke());
                    break;
                case "close":
                    graph.getElements().add(new Close());
                    break;
                case "rect":
                    Rect rect = new Rect();
                    rect.setX(Double.parseDouble(attributes.getValue("x")));
                    rect.setY(Double.parseDouble(attributes.getValue("y")));
                    rect.setW(Double.parseDouble(attributes.getValue("w")));
                    rect.setH(Double.parseDouble(attributes.getValue("h")));
                    graph.getElements().add(rect);
                    break;
                case "roundrect":
                    RoundRect roundRect = new RoundRect();
                    roundRect.setX(Double.parseDouble(attributes.getValue("x")));
                    roundRect.setY(Double.parseDouble(attributes.getValue("y")));
                    roundRect.setW(Double.parseDouble(attributes.getValue("w")));
                    roundRect.setH(Double.parseDouble(attributes.getValue("h")));
                    roundRect.setDx(Double.parseDouble(attributes.getValue("dx")));
                    roundRect.setDy(Double.parseDouble(attributes.getValue("dy")));
                    graph.getElements().add(roundRect);
                    break;
                case "ellipse":
                    Ellipse ellipse = new Ellipse();
                    ellipse.setX(Double.parseDouble(attributes.getValue("x")));
                    ellipse.setY(Double.parseDouble(attributes.getValue("y")));
                    ellipse.setW(Double.parseDouble(attributes.getValue("w")));
                    ellipse.setH(Double.parseDouble(attributes.getValue("h")));
                    graph.getElements().add(ellipse);
                    break;
                case "text":
                    Text text = new Text();
                    text.setX(Double.parseDouble(attributes.getValue("x")));
                    text.setY(Double.parseDouble(attributes.getValue("y")));
                    text.setW(Double.parseDouble(attributes.getValue("w")));
                    text.setH(Double.parseDouble(attributes.getValue("h")));
                    text.setStr(attributes.getValue("str"));
                    text.setAlign(attributes.getValue("align"));
                    text.setValign(attributes.getValue("valign"));
                    text.setWrap(Integer.parseInt(attributes.getValue("wrap")));
                    text.setFormat(attributes.getValue("format"));
                    text.setOverflow(attributes.getValue("overflow"));
                    text.setClip(Integer.parseInt(attributes.getValue("clip")));
                    text.setRotation(Double.parseDouble(attributes.getValue("rotation")));
                    graph.getElements().add(text);
                    break;
            }
        }
    }
}